/*!
 * \file nuRTTI.h
 * \brief Headder for Run-Time Type Information.
 * \author Nus
 * \date 2008/02/02, 21:50
 */

#ifndef __NURTTI_H__
#define __NURTTI_H__

#include "Types.h"
#include "Hash.h"

//! \name For base class.
//! \{

//! \brief Declare RTTI (for base class only).
#define DECLARE_RTTI(_class) \
private: \
class cRTTI : public nuRTTI \
{ \
public: \
cRTTI(); \
~cRTTI(); \
void* newObj(void) const; \
const s8* getName(void) const; \
static void constructRTTI(void) __attribute__((constructor)); \
static cRTTI mRTTI; \
}; \
public: \
static const cRTTI& RTTI(void) { return cRTTI::mRTTI; }

//! \brief Implement RTTI (for base class only).
#define IMPLEMENT_RTTI(_class) \
const s8* _class ## Name = #_class; \
_class::cRTTI _class::cRTTI::mRTTI; \
_class::cRTTI::cRTTI() { } \
_class::cRTTI::~cRTTI() { } \
void* _class::cRTTI::newObj(void) const { return new _class; } \
const s8* _class::cRTTI::getName(void) const { return _class ## Name; } \
void _class::cRTTI::constructRTTI(void) { \
_class::cRTTI::mRTTI.init(nuRTTI::TYPE_BASE_CLASS, _class ## Name, NULL); }

//! \brief Implement RTTI (for abstract base class only).
#define IMPLEMENT_RTTI_NO_INST(_class) \
const s8* _class ## Name = #_class; \
_class::cRTTI _class::cRTTI::mRTTI; \
_class::cRTTI::cRTTI() { } \
_class::cRTTI::~cRTTI() { } \
void* _class::cRTTI::newObj(void) const { return NULL; } \
const s8* _class::cRTTI::getName(void) const { return _class ## Name; } \
void _class::cRTTI::constructRTTI(void) { \
_class::cRTTI::mRTTI.init(nuRTTI::TYPE_BASE_CLASS | nuRTTI::TYPE_ABSTRACT, \
_class ## Name, NULL); }

//! \}

//! \name For derived class.
//! \{

//! \brief Begin RTTI declaration.
#define BEGIN_RTTI_DECL(_class) \
private: \
class cRTTI : public nuRTTI { \
public: \
cRTTI(); \
~cRTTI(); \
void init(u32 type, const s8* cls, const s8* spr); \
void* newObj(void) const; \
const s8* getName(void) const;

//! \brief RTTI declaration.
#define RTTI_DECL(_class, _parent) \
static cRTTI m ## _parent ## _class ## RTTI; \
static void construct ## _parent ## _class ## RTTI(void) __attribute__((constructor)); \

//! \brief End RTTI declaration.
#define END_RTTI_DECL(_class) \
}; \
static nuRTTI* mpRTTIChain; \
public: \
static const nuRTTI& RTTI(void) { return *mpRTTIChain; }

//! \brief Begin RTTI implementation.
#define BEGIN_RTTI_IMPL(_class) \
const s8* _class ## Name = #_class; \
nuRTTI* _class::mpRTTIChain = NULL

//! \brief RTTI implementation.
#define RTTI_IMPL(_class, _parent) \
const s8* _parent ## _class ## Name = #_parent; \
_class::cRTTI _class::cRTTI::m ## _parent ## _class ## RTTI; \
void _class::cRTTI::construct ## _parent ## _class ## RTTI(void) { \
_class::cRTTI::m ## _parent ## _class ## RTTI.init(nuRTTI::TYPE_DERIVED, \
_class ## Name, _parent ## _class ## Name); }

//! \brief End RTTI implementation.
#define END_RTTI_IMPL(_class) \
_class::cRTTI::cRTTI() { } \
_class::cRTTI::~cRTTI() { } \
void* _class::cRTTI::newObj(void) const { return new _class; } \
const s8* _class::cRTTI::getName(void) const { return _class ## Name; } \
void _class::cRTTI::init(u32 type, const s8* cls, const s8* spr) { \
nuRTTI::init(type, cls, spr); \
if(_class::mpRTTIChain) _class::mpRTTIChain->attachChain(this); \
else _class::mpRTTIChain = this; }

//! \brief Begin RTTI implementation (for abstract class).
#define BEGIN_RTTI_IMPL_NO_INST(_class) \
const s8* _class ## Name = #_class; \
nuRTTI* _class::mpRTTIChain = NULL

#define END_RTTI_IMPL_NO_INST(_class) \
_class::cRTTI::cRTTI() { } \
_class::cRTTI::~cRTTI() { } \
void* _class::cRTTI::newObj(void) const { return NULL; } \
const s8* _class::cRTTI::getName(void) const { return _class ## Name; } \
void _class::cRTTI::init(u32 type, const s8* cls, const s8* spr) { \
nuRTTI::init(type, cls, spr); \
if(_class::mpRTTIChain) _class::mpRTTIChain->attachChain(this); \
else _class::mpRTTIChain = this; }

//! \}

// Prototype: nuRTTI.
class nuRTTI;

/*!
 * \class nuRTTIMgr
 * \brief RTTI manager.
 * Looks like a singleton with no instance. Only for storing RTTI chain.
 */
class nuRTTIMgr
{
public:
  //! \brief Add RTTI.
  static void addRTTI(nuRTTI* p_class);
  
  //! \brief New object.
  static void* newObj(const char* name);

  //! \brief New object.
  static void* newObj(const nuRTTI& my_rtti);

  //! \brief Log RTTI
  static void logRTTI(void);

protected:
  // None.

private:
  static nuRTTI* mpRTTIChain;       //!< RTTI chain.
  static nuRTTI* mpLastRTTI;        //!< Last RTTI in chain.

  //! \brief Default constructor.
  //! \warning Unused function.
  nuRTTIMgr();
  
  //! \brief Default destructor.
  //! \warning Unused function.
  ~nuRTTIMgr();
  
};

/*!
 * \class nuRTTI
 * \brief Run-Time Type Information.
 */
class nuRTTI
{
  friend class nuRTTIMgr;

public:
  //! \brief Type.
  enum eRTTIType {
    TYPE_UNINITIALIZED = 0,
    TYPE_BASE_CLASS = 1 << 0,
    TYPE_ABSTRACT = 1 << 1,
    TYPE_DERIVED = 1 << 2,
  };

  //! \brief Default constructor.
  nuRTTI();
  
  //! \brief Default destructor.
  virtual ~nuRTTI();
  
  //! \brief Initialize.
  virtual void init(u32 type, const s8* cls, const s8* spr);
  
  //! \brief New object.
  virtual void* newObj(void) const = 0;
  
  //! \brief Get name.
  virtual const s8* getName(void) const = 0;
  
  //! \brief Operator equal.
  bool operator == (const nuRTTI& my_rtti) const {
    return (mType == my_rtti.mType) &&
           (mClassHash == my_rtti.mClassHash) &&
           (mSuperHash == my_rtti.mSuperHash);
  }
  
  //! \brief RTTI type.
  u32 getType(void) const {
    return mType;
  }

  //! \brief Attach RTTI chain.
  void attachChain(nuRTTI* ch) {
    if(!mpChain)
      mpChain = ch;
    else
      mpChain->attachChain(ch);
  }

protected:
  HashValue mClassHash;           //!< Hash value.
  HashValue mSuperHash;           //!< Super class hash value.
  u32 mType;                      //!< Type.
  nuRTTI* mpChain;                //!< RTTI chain.

private:
  nuRTTI* mpNext;                 //!< Next RTTI.

};

#endif
